From 3746587d5ecf639fb9ed75343aaf8f5b3d71812e Mon Sep 17 00:00:00 2001 From: Mqdd Date: Wed, 3 Dec 2025 14:01:39 +0700 Subject: Initial commit (done showing product based on keywords) --- src/pages/searchkey/[slug].jsx | 89 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/pages/searchkey/[slug].jsx (limited to 'src/pages/searchkey/[slug].jsx') diff --git a/src/pages/searchkey/[slug].jsx b/src/pages/searchkey/[slug].jsx new file mode 100644 index 00000000..f09520f4 --- /dev/null +++ b/src/pages/searchkey/[slug].jsx @@ -0,0 +1,89 @@ +import axios from 'axios'; +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import Seo from '@/core/components/Seo'; +import dynamic from 'next/dynamic'; +import { capitalizeEachWord } from '../../utils/capializeFIrstWord'; + +const BasicLayout = dynamic(() => + import('@/core/components/layouts/BasicLayout') +); +const ProductSearch = dynamic(() => + import('@/lib/product/components/ProductSearch') +); + +// const BASE_URL = process.env.NEXT_PUBLIC_SELF_HOST; +const BASE_URL = 'https://indoteknik.com'; + +export default function KeywordPage() { + const router = useRouter(); + const [result, setResult] = useState(null); + const [query, setQuery] = useState(null); + + // Ambil slug dari URL dinamis + const keywordSlug = router?.query?.slug || ''; + const keyword = keywordSlug.replace(/-/g, ' ').toLowerCase(); + const url = BASE_URL + router.asPath.split('?')[0]; + const slugTitle = capitalizeEachWord(keyword); + + // Fetch info dari Solr index "url_category_brand" + const getUrls = async (url) => { + try { + const response = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/url-category_brand?url=${url}` + ); + const data = response?.data?.response?.docs[0] || null; + setResult(data); + console.log('[🔍 result from API]', data); // Tambahin ini + } catch (error) { + console.error('Error fetching data:', error); + } + }; + + // Panggil fetch setelah router siap + useEffect(() => { + if (router.isReady) { + getUrls(url); + } + }, [router.isReady]); + + // Jika Solr index ditemukan, siapkan parameter pencarian + useEffect(() => { + if (result) { + const fq = `category_parent_ids:${result.category_id_i} AND manufacture_id_i:${result.brand_id_i}`; + const q = keyword || '*:*'; // keyword dari URL + console.log('SOLR QUERY:', { q, fq }); + setQuery({ fq, q }); + } + }, [result, keyword]); + + if (!result) { + return ( + + +
+

Produk tidak ditemukan berdasarkan keyword

+
+
+ ); + } + + return ( + + + {query && } + + ); +} -- cgit v1.2.3 From 9ca4e764383ffc3800fbe899dd7e07c297c51e75 Mon Sep 17 00:00:00 2001 From: Mqdd Date: Fri, 5 Dec 2025 10:50:31 +0700 Subject: fix query --- src/pages/searchkey/[slug].jsx | 50 +++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 15 deletions(-) (limited to 'src/pages/searchkey/[slug].jsx') diff --git a/src/pages/searchkey/[slug].jsx b/src/pages/searchkey/[slug].jsx index f09520f4..9cf1df05 100644 --- a/src/pages/searchkey/[slug].jsx +++ b/src/pages/searchkey/[slug].jsx @@ -47,26 +47,41 @@ export default function KeywordPage() { } }, [router.isReady]); - // Jika Solr index ditemukan, siapkan parameter pencarian useEffect(() => { if (result) { - const fq = `category_parent_ids:${result.category_id_i} AND manufacture_id_i:${result.brand_id_i}`; - const q = keyword || '*:*'; // keyword dari URL + let fqParts = []; + + if (result.category_id_i) { + fqParts.push(`category_parent_ids:${result.category_id_i}`); + } + + if (result.brand_id_i) { + fqParts.push(`manufacture_id_i:${result.brand_id_i}`); + } + + const fq = fqParts.join(' AND '); + const q = keyword || '*:*'; + console.log('SOLR QUERY:', { q, fq }); - setQuery({ fq, q }); + + setQuery({ + fq, + q, + from: 'searchkey', + }); } }, [result, keyword]); - if (!result) { - return ( - - -
-

Produk tidak ditemukan berdasarkan keyword

-
-
- ); - } + // if (!result) { + // return ( + // + // + //
+ //

Produk tidak ditemukan berdasarkan keyword

+ //
+ //
+ // ); + // } return ( @@ -83,7 +98,12 @@ export default function KeywordPage() { router.asPath.split('?')[0] }`} /> - {query && } + {query && ( + + )} ); } -- cgit v1.2.3 From 95b27ddb0604fbb4fae130f2d80e5ee2aec6d0fc Mon Sep 17 00:00:00 2001 From: Mqdd Date: Thu, 11 Dec 2025 09:00:03 +0700 Subject: fix --- src/pages/searchkey/[slug].jsx | 94 ++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 64 deletions(-) (limited to 'src/pages/searchkey/[slug].jsx') diff --git a/src/pages/searchkey/[slug].jsx b/src/pages/searchkey/[slug].jsx index 9cf1df05..3ebf6469 100644 --- a/src/pages/searchkey/[slug].jsx +++ b/src/pages/searchkey/[slug].jsx @@ -3,6 +3,7 @@ import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; import Seo from '@/core/components/Seo'; import dynamic from 'next/dynamic'; +import { getNameFromSlug } from '@/core/utils/slug'; import { capitalizeEachWord } from '../../utils/capializeFIrstWord'; const BasicLayout = dynamic(() => @@ -12,98 +13,63 @@ const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch') ); -// const BASE_URL = process.env.NEXT_PUBLIC_SELF_HOST; -const BASE_URL = 'https://indoteknik.com'; - -export default function KeywordPage() { - const router = useRouter(); +export default function FindPage() { + const route = useRouter(); const [result, setResult] = useState(null); const [query, setQuery] = useState(null); - // Ambil slug dari URL dinamis - const keywordSlug = router?.query?.slug || ''; - const keyword = keywordSlug.replace(/-/g, ' ').toLowerCase(); - const url = BASE_URL + router.asPath.split('?')[0]; - const slugTitle = capitalizeEachWord(keyword); + const slugRaw = route.query.slug || null; + console.log(slugRaw); + + // const cleanKey = slugRaw ? getNameFromSlug(slugRaw) : ''; + // console.log(cleanKey); + const readableSlug = capitalizeEachWord(slugRaw); - // Fetch info dari Solr index "url_category_brand" - const getUrls = async (url) => { + const getSearchKeyData = async (clean) => { try { - const response = await axios( - `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/url-category_brand?url=${url}` + const res = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/searchkey?url=${clean}&from=searchkey` ); - const data = response?.data?.response?.docs[0] || null; - setResult(data); - console.log('[🔍 result from API]', data); // Tambahin ini - } catch (error) { - console.error('Error fetching data:', error); + + setResult(res?.data?.response?.docs?.[0] || null); + } catch (e) { + console.error('Fetching searchkey failed:', e); } }; - // Panggil fetch setelah router siap useEffect(() => { - if (router.isReady) { - getUrls(url); - } - }, [router.isReady]); + if (!route.isReady) return; + if (!slugRaw) return; + + getSearchKeyData(slugRaw); + }, [route.isReady, slugRaw]); useEffect(() => { if (result) { - let fqParts = []; - - if (result.category_id_i) { - fqParts.push(`category_parent_ids:${result.category_id_i}`); - } - - if (result.brand_id_i) { - fqParts.push(`manufacture_id_i:${result.brand_id_i}`); - } - - const fq = fqParts.join(' AND '); - const q = keyword || '*:*'; - - console.log('SOLR QUERY:', { q, fq }); + const ids = result.product_ids_is || []; setQuery({ - fq, - q, + ids: ids.join(','), from: 'searchkey', }); } - }, [result, keyword]); - - // if (!result) { - // return ( - // - // - //
- //

Produk tidak ditemukan berdasarkan keyword

- //
- //
- // ); - // } + }, [result]); return ( - {query && ( - - )} + + {query && } ); } -- cgit v1.2.3 From 5808e82529933aee7c63ede955f64028fd1f38ee Mon Sep 17 00:00:00 2001 From: Mqdd Date: Tue, 16 Dec 2025 14:34:47 +0700 Subject: fix bug & add category --- src/pages/searchkey/[slug].jsx | 47 ++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 16 deletions(-) (limited to 'src/pages/searchkey/[slug].jsx') diff --git a/src/pages/searchkey/[slug].jsx b/src/pages/searchkey/[slug].jsx index 3ebf6469..4a6923ff 100644 --- a/src/pages/searchkey/[slug].jsx +++ b/src/pages/searchkey/[slug].jsx @@ -3,9 +3,11 @@ import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; import Seo from '@/core/components/Seo'; import dynamic from 'next/dynamic'; -import { getNameFromSlug } from '@/core/utils/slug'; import { capitalizeEachWord } from '../../utils/capializeFIrstWord'; +// ✅ Breadcrumb = default export +import Breadcrumb from '@/lib/category/components/Breadcrumb'; + const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout') ); @@ -15,20 +17,19 @@ const ProductSearch = dynamic(() => export default function FindPage() { const route = useRouter(); + const [result, setResult] = useState(null); const [query, setQuery] = useState(null); + const [categoryId, setCategoryId] = useState(null); const slugRaw = route.query.slug || null; - console.log(slugRaw); - - // const cleanKey = slugRaw ? getNameFromSlug(slugRaw) : ''; - // console.log(cleanKey); const readableSlug = capitalizeEachWord(slugRaw); - const getSearchKeyData = async (clean) => { + // 🔹 Fetch searchkey dari Solr + const getSearchKeyData = async (slug) => { try { const res = await axios( - `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/searchkey?url=${clean}&from=searchkey` + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/searchkey?url=${slug}&from=searchkey` ); setResult(res?.data?.response?.docs?.[0] || null); @@ -37,21 +38,31 @@ export default function FindPage() { } }; + // 🔹 Trigger fetch saat slug siap useEffect(() => { - if (!route.isReady) return; - if (!slugRaw) return; - + if (!route.isReady || !slugRaw) return; getSearchKeyData(slugRaw); }, [route.isReady, slugRaw]); + // 🔹 Ambil product_ids + categoryId dari Solr useEffect(() => { - if (result) { - const ids = result.product_ids_is || []; + if (!result) return; - setQuery({ - ids: ids.join(','), - from: 'searchkey', - }); + // product search + const ids = result.product_ids_is || []; + setQuery({ + ids: ids.join(','), + from: 'searchkey', + }); + + // breadcrumb category + const catId = + result.category_id_i || + result.public_categ_id_i || + (result.category_ids_is && result.category_ids_is[0]); + + if (catId) { + setCategoryId(catId); } }, [result]); @@ -69,6 +80,10 @@ export default function FindPage() { canonical={`${process.env.NEXT_PUBLIC_SELF_HOST}${route.asPath}`} /> + {/* ✅ Breadcrumb (auto fetch via component) */} + {categoryId && } + + {/* ✅ Product result */} {query && } ); -- cgit v1.2.3 From 89978029f6f97bd1bb4390a3e3c2edf073e115c9 Mon Sep 17 00:00:00 2001 From: Mqdd Date: Fri, 19 Dec 2025 15:15:28 +0700 Subject: fix title --- src/pages/searchkey/[slug].jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/pages/searchkey/[slug].jsx') diff --git a/src/pages/searchkey/[slug].jsx b/src/pages/searchkey/[slug].jsx index 4a6923ff..a23f11b0 100644 --- a/src/pages/searchkey/[slug].jsx +++ b/src/pages/searchkey/[slug].jsx @@ -23,7 +23,11 @@ export default function FindPage() { const [categoryId, setCategoryId] = useState(null); const slugRaw = route.query.slug || null; - const readableSlug = capitalizeEachWord(slugRaw); + const readableSlug = slugRaw + ? decodeURIComponent(slugRaw) + .replace(/-/g, ' ') + .replace(/\b\w/g, (c) => c.toUpperCase()) + : ''; // 🔹 Fetch searchkey dari Solr const getSearchKeyData = async (slug) => { -- cgit v1.2.3 From 4d5dbcda7334c90b54ad25d828c8cf2a6433b682 Mon Sep 17 00:00:00 2001 From: Mqdd Date: Fri, 19 Dec 2025 15:25:10 +0700 Subject: add keyword to breadcrumb --- src/pages/searchkey/[slug].jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/pages/searchkey/[slug].jsx') diff --git a/src/pages/searchkey/[slug].jsx b/src/pages/searchkey/[slug].jsx index a23f11b0..82179b7d 100644 --- a/src/pages/searchkey/[slug].jsx +++ b/src/pages/searchkey/[slug].jsx @@ -85,7 +85,9 @@ export default function FindPage() { /> {/* ✅ Breadcrumb (auto fetch via component) */} - {categoryId && } + {categoryId && ( + + )} {/* ✅ Product result */} {query && } -- cgit v1.2.3 From 8c4d73ff159cb7b5df4f83f1eb76e8a06c7179ce Mon Sep 17 00:00:00 2001 From: Mqdd Date: Fri, 19 Dec 2025 16:08:14 +0700 Subject: fix page name --- src/pages/searchkey/[slug].jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pages/searchkey/[slug].jsx') diff --git a/src/pages/searchkey/[slug].jsx b/src/pages/searchkey/[slug].jsx index 82179b7d..b0fc9ab8 100644 --- a/src/pages/searchkey/[slug].jsx +++ b/src/pages/searchkey/[slug].jsx @@ -15,7 +15,7 @@ const ProductSearch = dynamic(() => import('@/lib/product/components/ProductSearch') ); -export default function FindPage() { +export default function KeywordPage() { const route = useRouter(); const [result, setResult] = useState(null); -- cgit v1.2.3 From 4a85f437cfa7a61bebd341c9a509abccbd64745b Mon Sep 17 00:00:00 2001 From: Mqdd Date: Wed, 18 Feb 2026 17:26:59 +0700 Subject: fix pagination --- src/pages/searchkey/[slug].jsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src/pages/searchkey/[slug].jsx') diff --git a/src/pages/searchkey/[slug].jsx b/src/pages/searchkey/[slug].jsx index b0fc9ab8..2fa3cf8d 100644 --- a/src/pages/searchkey/[slug].jsx +++ b/src/pages/searchkey/[slug].jsx @@ -8,11 +8,11 @@ import { capitalizeEachWord } from '../../utils/capializeFIrstWord'; // ✅ Breadcrumb = default export import Breadcrumb from '@/lib/category/components/Breadcrumb'; -const BasicLayout = dynamic(() => - import('@/core/components/layouts/BasicLayout') +const BasicLayout = dynamic( + () => import('@/core/components/layouts/BasicLayout'), ); -const ProductSearch = dynamic(() => - import('@/lib/product/components/ProductSearch') +const ProductSearch = dynamic( + () => import('@/lib/product/components/ProductSearch'), ); export default function KeywordPage() { @@ -33,7 +33,7 @@ export default function KeywordPage() { const getSearchKeyData = async (slug) => { try { const res = await axios( - `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/searchkey?url=${slug}&from=searchkey` + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/searchkey?url=${slug}&from=searchkey`, ); setResult(res?.data?.response?.docs?.[0] || null); @@ -52,7 +52,7 @@ export default function KeywordPage() { useEffect(() => { if (!result) return; - // product search + // product search - keep ids for API, add from marker for ProductSearch const ids = result.product_ids_is || []; setQuery({ ids: ids.join(','), @@ -90,7 +90,9 @@ export default function KeywordPage() { )} {/* ✅ Product result */} - {query && } + {query && ( + + )} ); } -- cgit v1.2.3 From 7b79adcbcf0ef7c791e0c679ca946243c9dde7f7 Mon Sep 17 00:00:00 2001 From: Mqdd Date: Thu, 19 Feb 2026 16:50:59 +0700 Subject: fix cannonical tag --- src/pages/searchkey/[slug].jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pages/searchkey/[slug].jsx') diff --git a/src/pages/searchkey/[slug].jsx b/src/pages/searchkey/[slug].jsx index 2fa3cf8d..fbe72dae 100644 --- a/src/pages/searchkey/[slug].jsx +++ b/src/pages/searchkey/[slug].jsx @@ -81,7 +81,7 @@ export default function KeywordPage() { content: `Beli ${readableSlug}, harga ${readableSlug}, ${readableSlug} murah`, }, ]} - canonical={`${process.env.NEXT_PUBLIC_SELF_HOST}${route.asPath}`} + canonical={`${process.env.NEXT_PUBLIC_SELF_HOST}/searchkey/${slugRaw}`} /> {/* ✅ Breadcrumb (auto fetch via component) */} -- cgit v1.2.3